1. РАБОТА СО СТРОКАМИ В JAVA 

В Java имеется три типа строк:

1.       статические строки «String» - обычные строки в Java, в которых нельзя изменить символы и их количество после создания строки;

2.       динамические строки «StringBuilder» – изменяемые строки для использования в однопоточных программах. В однопоточном использовании StringBuilder практически всегда в 1.2-1.5 раза быстрее, чем StringBuffer;

3.       динамические строки StringBuffer – изменяемые строки для использования в многопоточных программах. Самый медленный тип, но потокобезопасный.

Переменные типа динамических строк могут менять свои значения и длину во время выполнения программы.

1.1. СТАТИЧЕСКИЕ СТРОКИ

Обычные строки в Java описываются классом String и являются статическими, т.е. в существующей строке нельзя изменить символы и их количество.

Кроме стандартного создания оператором new, строки могут быть созданы напрямую из строковой литералы. При этом в целях оптимизации, объекты созданные таким образом дополнительно сохраняются в отдельной области - строковый пул.

String s1 = "d" // строка будет сохранена в пуле

// строка не будет сохранена в пуле и будет уничтожена сборщиком мусора

String s2 = new String("a");

Один из плюсов разделения строк на статические и динамические - повышение безопасности там, где строки используются в качестве аргументов (например, открытие баз данных, интернет соединений, механизм загрузки классов).

Операция сцепления

Для строк доступна операция +, позволяющая соединить несколько строк в одну. Если один из операндов не строка, то он автоматически преобразуется в строку. Для объектов в этих целях используется метод toString.

При каждой операции внутренне используется объект динамической строки StringBuilder или StringBuffer. Поэтому для собирания строки из нескольких все равно оптимальней использовать сразу один StringBuilder/StringBuffer.

Выделение подстроки

Есть замечание относительно метода substring - возвращаемая строка использует тот же байтовый массив, что и исходная. Например, вы загрузили строку А из файла в 1мб. Что-то там нашли и выделили в отдельную строку Б длиной в 3 символа. Строка Б в реальности тоже занимает те же 1мб.

String s ="very .... long string from file";

String sub1 = s.substring(2,4); // совместно использует ту же память что и s

String sub2 = new String(s.substring(2,4)); // этот объект использует отдельный массив на 4 символа

Основные методы

·       equals(Object anObject) - проверяет, идентична ли строка указанному объекту;

·       compareTo(String anotherString) - лексиграфическое сравнение строк;

·       compareToIgnoreCase(String str) - лексиграфическое сравнение строк без учета регистра символов;

·       concat(String str) - возвращает соединение двух строк;

·       contains(CharSequence s) - проверяет, входит ли указанная последовательность символов в строку;

·       isEmpty() – возвращает true, если длина строки равна 0;

·       indexOf(String str) - поиск первого вхождения указанной подстроки;

·       replace(CharSequence target, CharSequence replacement) - замена одной подстроки другой;

·       substring(int beginIndex, int endIndex) - возвратить подстроку как строку;

·       toLowerCase() - преобразовать строку в нижний регистр;

·       toUpperCase() - преобразовать строку в верхний регистр;

·       trim() - отсечь на концах строки пустые символы;

·       length() – определение длины строки;

·       valueOf(a) - статические методы преобразования различных типов в строку;

·       charAt(int index) - возвращает символ по указанному индексу;

·       regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len) - тест на идентичность участков строк, можно указать учет регистра символов;

·       regionMatches(int toffset, String other, int ooffset, int len) - тест на идентичность участков строк;

·       endsWith(String suffix) - проверяет, завершается ли строка указанным суффиксом;

·       startsWith(String prefix) - проверяет, начинается ли строка с указанного префикса;

·       startsWith(String prefix, int toffset) - проверяет, начинается ли строка в указанной позиции с указанного префикса;

·       getBytes() - возвращает байтовое представление строки;

·       getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) - возвращает символьное представление участка строки;

·       hashCode() - хеш код строки;

·       indexOf(int ch) - поиск первого вхождения символа в строке;

·       indexOf(int ch, int fromIndex) - поиск первого вхождения символа в строке с указанной позиции;

·       indexOf(String str, int fromIndex) - поиск первого вхождения указанной подстроки с указанной позиции;

·       lastIndexOf(int ch) - поиск последнего вхождения символа;

·       lastIndexOf(int ch, int fromIndex) - поиск последнего вхождения символа с указанной позиции;

·       lastIndexOf(String str) - поиск последнего вхождения строки;

·       lastIndexOf(String str, int fromIndex) - поиск последнего вхождения строки с указанной позиции;

·       replace(char oldChar, char newChar) - замена в строке одного символа на другой;

·       toUpperCase(Locale locale) - преобразовать строку в верхний регистр, используя указанную локализацию;

·       toLowerCase(Locale locale) - преобразовать строку в нижний регистр, используя указанную локализацию.

Методы поиска возвращают индекс вхождения или -1 если искомое не найдено. Методы преобразования как replace не изменяют саму строку, а возвращают соответствующий новый объект строки.

Особенности

public static void main(String[] args) {

String s = "a";

for (int i = 0; i < 100; i++) {

s += 'a';

}

System.out.println(s); // Распечатается строка из 100 символов «a»

}

Этот код создаст 100 разных строк, которые будут храниться в памяти, пока сборщик мусора не удалит их после завершения программы! В результате работы программы переменная «s» будет содержать строку из 100 символов «a», но 99  ранее созданных строк остались «мусором» в памяти без возможности обращения к ним!

Поэтому для изменения строки следует использовать класс обертку StringBuilder. Предыдущий пример нужно переписать следующим образом:

public static void main(String[] args) {

StringBuilder s = new StringBuilder("a");

for (int i = 0; i < 100; i++) {

s.append('a');

}

System.out.println(s); // Распечатается строка из 100 символов «a»

}

1.2. ДИНАМИЧЕСКИЕ СТРОКИ

Динамические строки описываются классами StringBuilder и StringBuffer. StringBuffer более медленный, но потокобезопасный. Переменные типа динамических строк могут менять свои значения и длину во время выполнения программы. Основные методы динамических строк:

·       append(A) - преобразовать A в строку и добавить в конец;

·       insert(int offset, A) - преобразовать A в строку и вставить ее в указанную позицию;

·       delete(int start, int end) - удалить символы с указанной по указанную позицию;

·       reverse() - расположить символы в обратном порядке;

·       setCharAt(int index, char ch) - заменить символ в указанной позиции;

·       setLength(int newLength) - установить новый размер строки;

·       substring(int start) - вернуть подстроку с указанной позиции и до конца как строку;

·       substring(int start, int end) - вернуть подстроку как строку;

·       deleteCharAt(int index) - удалить символ в указанной позиции;

·       getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) - сохранить последовательность символов в массив;

·       indexOf(String str) - поиск первого вхождения подстроки;

·       indexOf(String str, int fromIndex) - поиск первого вхождения подстроки с указанной позиции;

·       lastIndexOf(String str) - поиск последнего вхождения подстроки;

·       lastIndexOf(String str, int fromIndex) - поиск последнего вхождения подстроки с указанной позиции;

·       replace(int start, int end, String str) - замена участка строки указанной строкой.

1.3. ПРИМЕРЫ РАБОТЫ СО СТРОКАМИ

1.3.1. Пример 1 – Преобразования строк

В этом примере массив символов и целое число преобразуются в объекты типа String с использованием методов этого класса:

package tsn01.string;

public class TSN01_String {

public static void main(String[] args) {

// Пример работы со строками 1

char s[] = {'J', 'a', 'v', 'a'}; // Массив символов

String str = new String(s); // str="Java"

if (!str.isEmpty()) {

int i = str.length(); // i=4

str = str.toUpperCase(); // str="JAVA"

String num = String.valueOf(6); // num="6"

num = str.concat("-" + num); // num="JAVA-6"

char ch = str.charAt(2); // ch='V'

i = str.lastIndexOf('A'); // i=3 (-1 если нет)

num = num.replace("6", "SE"); // num="JAVA-SE"

str.substring(0, 4).toLowerCase(); // java

str = num + "-6";// str="JAVA-SE-6"

String[] arr = str.split("-");

for (String ss : arr) { // В результате будет выведен массив строк (в 3 строчки):  JAVA SE 6

System.out.println(ss);

}

} else {  System.out.println("String is empty!"); }

}

}

1.3.2. Пример 2 – Сравнение строк

В этом примере рассмотрены особенности хранения и идентификации объектов на примере вызова метода equals(), сравнивающего строку String с указанным объектом и метода hashCode(), который вычисляет хэш-код объекта (hashCode - это цифра, которая формируется для объекта по какому то правилу, например для объекта класса String по такой формуле: s[0]*31^(n-1) s[1]*31^(n-2) ... s[n-1]):

package tsn01.string;

public class TSN01_String {

public static void main(String[] args) {

// Пример работы со строками 2

String s1 = "Java";

String s2 = "Java";

String s3 = new String("Java");

System.out.println(s1 + "==" + s2 + " : " + (s1 == s2)); // true

System.out.println(s1 + "==" + s3 + " : " + (s1 == s3)); // false

System.out.println(s1 + " equals " + s2 + " : " + s1.equals(s2)); // true

System.out.println(s1 + " equals " + s3 + " : " + s1.equals(s3)); // true

System.out.println(s1.hashCode());

System.out.println(s2.hashCode());

System.out.println(s3.hashCode());

}

}

В результате на экран  будет выведено:

Java==Java : true

Java==Java : false

Java equals Java : true

Java equals Java : true

2301506

2301506

2301506

1.3.3. Пример 3 – Сортировка массива строк

Ниже рассмотрен пример сортировки массива строк методом выбора:

package tsn01.string;

public class TSN01_String {

public static void main(String[] args) {

// Пример работы со строками 3

String a[] = {" Alena", "Alice ", " alina", " albina", " Anastasya",

" ALLA ", "AnnA "}; // Массив строк

for (int j = 0; j < a.length; j++) { // Цикл по массиву строк

// Удаляем пробелы с концов строк и приводим к верхнему регистру

a[j] = a[j].trim().toLowerCase();

}

// Сортировка строк методом пузырька

for (int j = 0; j < a.length - 1; j++) { // Цикл по массиву строк

for (int i = j + 1; i < a.length; i++) { // Цикл по массиву строк

if (a[i].compareTo(a[j]) < 0) { // Сравнение строк

String temp = a[j]; a[j] = a[i]; a[i] = temp; // Обмен значений в массиве строк

}

}

}

int i = -1;

while (++i < a.length) { System.out.print(a[i] + " "); } // Вывод массива строк на экран

}

}

В результате на экран  будет выведено:

albina alena alice alina alla anastasya anna

Вызов метода trim() обеспечивает удаление всех начальных и конечных символов пробелов. Метод compareTo() выполняет лексикографическое сравнение строк между собой по правилам Unicode.

1.3.4. Пример 4 – Работа с динамическими строками

Пример преобразования переменной  типа «StringBuilder» к «String» через метод toString:

package tsn01.string;

public class TSN01_String {

public static void main(String[] args) {

// Пример работы со строками 4

StringBuilder s = new StringBuilder("abcd");

s.append('e');//abcde

s.delete(1, 2);//acde

s.insert(1, 'b');//abcde

s.deleteCharAt(2);//abde

String ans = s.toString();

System.out.println(ans); // На экран выведется "abde"

}

}